<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>GtkTextView Widget</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, GtkTextView Widget, GTK+ library, C">
<meta name="description" content="GtkTextView Widget">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>GtkTextView Widget</h1>


<p>
In this part of the GTK+ programming tutorial, we will work with a GtkTextView widget. 
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>

<p>
<b class="keyword">GtkTextView</b> widget is used for displaying and 
editing multiline text. GtkTextView widget has also the MVC design. The 
GtkTextView represents the view component and <b class="keyword">GtkTextBuffer</b> 
represents the model component. The GtkTextBuffer is used to manipulate 
the text data. <b class="keyword">GtkTextTag</b> is an attribute that 
can be applied to the text. The <b class="keyword">GtkTextIter</b> represents 
a position between two characters in the text. All manipulation with the 
text is done using text iterators. 
</p>

<h2>Simple example</h2>

<p>
In our first example, we show some of the GtkTextView's functionality. 
We show how to apply various text tags to the text data in the GtkTextView. 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *view;
  GtkWidget *vbox;
  
  GtkTextBuffer *buffer;
  GtkTextIter start, end;
  GtkTextIter iter;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "TextView");
  gtk_container_set_border_width(GTK_CONTAINER(window), 5);
  GTK_WINDOW(window)->allow_shrink = TRUE;

  vbox = gtk_vbox_new(FALSE, 0);
  view = gtk_text_view_new();
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));

  gtk_text_buffer_create_tag(buffer, "gap",
        "pixels_above_lines", 30, NULL);

  gtk_text_buffer_create_tag(buffer, "lmarg", 
      "left_margin", 5, NULL);
  gtk_text_buffer_create_tag(buffer, "blue_fg", 
      "foreground", "blue", NULL); 
  gtk_text_buffer_create_tag(buffer, "gray_bg", 
      "background", "gray", NULL); 
  gtk_text_buffer_create_tag(buffer, "italic", 
      "style", PANGO_STYLE_ITALIC, NULL);
  gtk_text_buffer_create_tag(buffer, "bold", 
      "weight", PANGO_WEIGHT_BOLD, NULL);

  gtk_text_buffer_get_iter_at_offset(buffer, &amp;iter, 0);

  gtk_text_buffer_insert(buffer, &amp;iter, "Plain text\n", -1);
  gtk_text_buffer_insert_with_tags_by_name(buffer, &amp;iter, 
        "Colored Text\n", -1, "blue_fg", "lmarg",  NULL);
  gtk_text_buffer_insert_with_tags_by_name (buffer, &amp;iter, 
        "Text with colored background\n", -1, "lmarg", "gray_bg", NULL);

  gtk_text_buffer_insert_with_tags_by_name (buffer, &amp;iter, 
        "Text in italics\n", -1, "italic", "lmarg",  NULL);

  gtk_text_buffer_insert_with_tags_by_name (buffer, &amp;iter, 
        "Bold text\n", -1, "bold", "lmarg",  NULL);

  gtk_container_add(GTK_CONTAINER(window), vbox);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), G_OBJECT(window));

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
The example shows some text with different <b class="keyword">GtkTextTags</b> applied.
</p>

<pre class="explanation">
 view = gtk_text_view_new();
</pre>

<p>
The <b class="keyword">GtkTextView</b> is created. 
</p>

<pre class="explanation">
 gtk_text_buffer_create_tag(buffer, "blue_fg", 
     "foreground", "blue", NULL); 
</pre>

<p>
This is an example of a <b class="keyword">GtkTextTag</b>. The tag changes 
the color of the text to blue. 
</p>

<pre class="explanation">
 gtk_text_buffer_insert_with_tags_by_name(buffer, &amp;iter, 
       "Colored Text\n", -1, "blue_fg", "lmarg",  NULL);
</pre>

<p>
This code inserts some text with a specific <b class="keyword">blue_fg</b> text tag. 
</p>

<br>
<img src="/img/gui/cgtk/simpletextview.png" alt="Simple TextView">
<div class="figure">Figure: Simple TextView</div>
<br>

<h2>Lines and Columns</h2>

<p>
The following example will display the current line and column of the text cursor.  
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;

update_statusbar(GtkTextBuffer *buffer,
    GtkStatusbar  *statusbar)
{
  gchar *msg;
  gint row, col;
  GtkTextIter iter;

  gtk_statusbar_pop(statusbar, 0); 

  gtk_text_buffer_get_iter_at_mark(buffer,
      &amp;iter, gtk_text_buffer_get_insert(buffer));

  row = gtk_text_iter_get_line(&amp;iter);
  col = gtk_text_iter_get_line_offset(&amp;iter);

  msg = g_strdup_printf("Col %d Ln %d", col+1, row+1);

  gtk_statusbar_push(statusbar, 0, msg);

  g_free(msg);
}

static void
mark_set_callback(GtkTextBuffer *buffer,
    const GtkTextIter *new_location, GtkTextMark *mark,
    gpointer data)
{
  update_statusbar(buffer, GTK_STATUSBAR(data));
}


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;

  GtkWidget *toolbar;
  GtkWidget *view;
  GtkWidget *statusbar;
  GtkToolItem *exit;
  GtkTextBuffer *buffer;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "lines &amp; cols");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);

  toolbar = gtk_toolbar_new();
  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);

  exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);

  gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);

  view = gtk_text_view_new();
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);
  gtk_widget_grab_focus(view);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));

  statusbar = gtk_statusbar_new();
  gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);

  g_signal_connect(G_OBJECT(exit), "clicked", 
        G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect(buffer, "changed",
        G_CALLBACK(update_statusbar), statusbar);

  g_signal_connect_object(buffer, "mark_set", 
        G_CALLBACK(mark_set_callback), statusbar, 0);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  update_statusbar(buffer, GTK_STATUSBAR (statusbar));

  gtk_main();

  return 0;
}
</pre>

<p>
In this code example, we show the current position of the text cursor in the statusbar. 
</p>

<pre class="explanation">
 view = gtk_text_view_new();
</pre>

<p>
The <b class="keyword">GtkTextView</b> widget is created. 
</p>

<pre class="explanation">
 g_signal_connect(buffer, "changed",
       G_CALLBACK(update_statusbar), statusbar);
</pre>

<p>
When we change the text, we call the <b class="keyword">update_statusbar()</b> handler.
</p>

<pre class="explanation">
 g_signal_connect_object(buffer, "mark_set", 
       G_CALLBACK(mark_set_callback), statusbar, 0);
</pre>

<p>
The <b class="keyword">mark_set</b> signal is emitted, when the cursor moves. 
</p>

<pre class="explanation">
 gtk_statusbar_pop(statusbar, 0); 
</pre>

<p>
 This code line clears any previous message from the statusbar.
</p>

<pre class="explanation">
 gtk_text_buffer_get_iter_at_mark(buffer,
     &amp;iter, gtk_text_buffer_get_insert(buffer));

 row = gtk_text_iter_get_line(&amp;iter);
 col = gtk_text_iter_get_line_offset(&amp;iter);
</pre>

<p>
These lines determine the current line/row and column.  
</p>

<pre class="explanation">
 msg = g_strdup_printf("Col %d Ln %d", col+1, row+1);
</pre>

<p>
This code builds the text to be displayed on the statusbar. 
</p>


<pre class="explanation">
 gtk_statusbar_push(statusbar, 0, msg);
</pre>

<p>
We show the text on the statusbar. 
</p>

<br>
<img src="/img/gui/cgtk/linesandcols.png" alt="Lines & Columns">
<div class="figure">Figure: Lines and Columns</div>
<br>


<h2>Search &amp; Highlight</h2>

<p>
In the next example, we will do some searching in the <b class="keyword">GtkTextBuffer</b>. 
We will highlight some text patterns in the text buffer. 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;
#include &lt;gdk/gdkkeysyms.h&gt;



gboolean key_pressed(GtkWidget * window,
    GdkEventKey* event, GtkTextBuffer *buffer) {

  GtkTextIter start_sel, end_sel;
  GtkTextIter start_find, end_find;
  GtkTextIter start_match, end_match;
  gboolean selected;	
  gchar *text;		  
  


  if ((event->type == GDK_KEY_PRESS) &amp;&amp; 
     (event->state &amp; GDK_CONTROL_MASK)) {

    switch (event->keyval)
    {
      case GDK_m :
        selected = gtk_text_buffer_get_selection_bounds(buffer, 
            &amp;start_sel, &amp;end_sel);
      if (selected) {
        gtk_text_buffer_get_start_iter(buffer, &amp;start_find);
        gtk_text_buffer_get_end_iter(buffer, &amp;end_find);

        gtk_text_buffer_remove_tag_by_name(buffer, "gray_bg", 
            &amp;start_find, &amp;end_find);  
        text = (char *) gtk_text_buffer_get_text(buffer, &amp;start_sel,
            &amp;end_sel, FALSE);

        while ( gtk_text_iter_forward_search(&amp;start_find, text, 
                GTK_TEXT_SEARCH_TEXT_ONLY | 
                GTK_TEXT_SEARCH_VISIBLE_ONLY, 
                &amp;start_match, &amp;end_match, NULL) ) {

          gtk_text_buffer_apply_tag_by_name(buffer, "gray_bg", 
              &amp;start_match, &amp;end_match);
          int offset = gtk_text_iter_get_offset(&amp;end_match);
          gtk_text_buffer_get_iter_at_offset(buffer, 
              &amp;start_find, offset);
        }

        g_free(text);
      }

      break;

      case GDK_r:
        gtk_text_buffer_get_start_iter(buffer, &amp;start_find);
        gtk_text_buffer_get_end_iter(buffer, &amp;end_find);
      
        gtk_text_buffer_remove_tag_by_name(buffer, "gray_bg", 
            &amp;start_find, &amp;end_find);  
      break;
    }
  }

  return FALSE;
}


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *view;
  GtkWidget *vbox;
  
  GtkTextBuffer *buffer;
  GtkTextIter start, end;
  GtkTextIter iter;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "Search &amp; Highlight");
  gtk_container_set_border_width(GTK_CONTAINER(window), 5);
  GTK_WINDOW(window)->allow_shrink = TRUE;

  vbox = gtk_vbox_new(FALSE, 0);
  view = gtk_text_view_new();
  gtk_widget_add_events(view, GDK_BUTTON_PRESS_MASK);
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
  gtk_text_buffer_create_tag(buffer, "gray_bg", 
      "background", "gray", NULL); 
  gtk_container_add(GTK_CONTAINER(window), vbox);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), G_OBJECT(window));

  g_signal_connect(G_OBJECT(window), "key-press-event",
        G_CALLBACK(key_pressed), buffer);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
In our code example we use keyboard shortcuts. The Ctrl + M shortcut highlights 
the all occurrences of currently
selected text. The Ctrl + R removes the highlights from the text.  
</p>

<pre class="explanation">
 gtk_text_buffer_create_tag(buffer, "gray_bg", 
     "background", "gray", NULL); 
</pre>

<p>
This is the <b class="keyword">GtkTextTag</b> that we use in our example. The tag makes the background
of the text gray. 
</p>

<pre class="explanation">
 selected = gtk_text_buffer_get_selection_bounds(buffer, 
     &amp;start_sel, &amp;end_sel);
</pre>

<p>
Here we get the start and end positions of the selected text. 
</p>


<pre class="explanation">
gtk_text_buffer_get_start_iter(buffer, &amp;start_find);
gtk_text_buffer_get_end_iter(buffer, &amp;end_find);
</pre>

<p>
We get the first and last position in the text buffer. 
</p>


<pre class="explanation">
gtk_text_buffer_remove_tag_by_name(buffer, "gray_bg", 
    &amp;start_find, &amp;end_find);  
</pre>

<p>
We remove any previous text tag. 
</p>

<pre class="explanation">
 text = (char *) gtk_text_buffer_get_text(buffer, &amp;start_sel,
     &amp;end_sel, FALSE);
</pre>

<p>
We obtain the selected text. It is the text, we are going to search for. 
</p>

<pre class="explanation">
while ( gtk_text_iter_forward_search(&amp;start_find, text, 
        GTK_TEXT_SEARCH_TEXT_ONLY | 
        GTK_TEXT_SEARCH_VISIBLE_ONLY, 
        &amp;start_match, &amp;end_match, NULL) ) {

  gtk_text_buffer_apply_tag_by_name(buffer, "gray_bg", 
      &amp;start_match, &amp;end_match);
  int offset = gtk_text_iter_get_offset(&amp;end_match);
  gtk_text_buffer_get_iter_at_offset(buffer, 
      &amp;start_find, offset);
}
</pre>

<p>
This code searches for all occurences of our selected text. If we find any match, we
apply the text tag. After the match, the ending point of the word becomes the starting point
for the next search.
</p>


<br>
<img src="/img/gui/cgtk/searchhighlight.png" alt="Search &amp; Highlight">
<div class="figure">Figure: Search &amp; Highlight</div>
<br>

<hr class="btm">

<p>
In this chapter we covered GtkTextView widget. 
</p>

<br>
<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified March 29, 2008  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

